home *** CD-ROM | disk | FTP | other *** search
Text File | 1987-01-14 | 51.4 KB | 1,699 lines |
-
- c program xmodem50
-
- c ATTEMPTED TO USE LIB$CRC
- c THIS DOES NOT WORK FOR UNKNOWN REASONS
-
- c MODEM7-type program to send and
- c receive files with checksums or CRC and automatic
- c re-transmission of bad blocks.
- c translated to VAX Fortran V3.0 from TMODEM.C
- c and enhanced according to time-outs and CRC
- c in XMODEM50.ASM
- c J.James Belonis II
- c Physics Hall FM-15
- c University of Washington
- c Seattle, WA 98195
- c (206) 545-8695
- c
- c TMODEM.C written by Richard Conn, Eliot Moss, and Lauren
- c Weinstein
- c
- c 3/17/84 changed to LIB$CRC VAX system service. Left old updcrc
- c and associated routines in place, commented out.
- c 3/13/84 reserved space in cancel for eating characters to avoid access viol
- c 3/13/84 increased RECVFILE data block timeout to 2 sec
- c 2/27/84 Version 5.5 incorporated improvements by Steve Gill
- c GETACK timeout and garbage loop and NAK, CAN detection
- c RECVFILE receive data block with timeout
- c TTYIN routine removed since replaced everywhere by TTYINLIM
- c 1/25/84 properly placed CALL PASSALL in main program so not miss parity bit
- c in sendfn filename checksum
- c 1/ 8/84 corrected last known bugs
- c 1/ 2/84 Version 5.4 Added batch
- c 12/31/83 Version 5.3 Added wildcard filenames(but not yet batch) and
- c streamlined option parsing and allowed CRC TEXT
- c found and fixed blank trim miscalculation
- c again (CONN apparently got old version)
- c XMODEM.LOG and XMODEM.WRK put in SYS$SCRATCH directory
- c (usually user's main) if can't open in current directory
- c 12/27/83 Version 5.2 Speeded up SEND by doing only one TTYOUT call per block.
- c no longer hogs CPU at 9600 baud (only 15-20 percent of cpu time)
- c included QIO.DCK so only one file XMODEM.FOR is needed.
- c 6/30/83 Modified, restructured, and VAX/VMS text file
- c conversion added by Richard Conn
- c 1/17/83 touched up filename display and comments.
- c 1/14/83 including timeouts and CTRL-X cancellation
- c and CRC capability
- c
- c keeps a log file of error messages ( deletes it if no errors )
- c sets terminal driver to eightbit, passall
- c may need altypeahd if faster than 1200 baud works to 9600 baud at least.
- c needs PHY_IO privilege for passall ? apparently not on UWPhys VAX
- c nor on ACC VAX
- c many debugging statements left in as comments
-
- c declare variables
-
- include '($rmsdef)' ! for LIB$FIND_FILE
- INTEGER*2 CHAN,STATUS(4)
- COMMON /QIO/ CHAN,STATUS
-
- character*128 line, filein, file, filec, filed, workf, options
- integer seploc, worklen, context, istat, length, lengthin
- logical openok, sendopt, recvopt, textopt
- logical getfn, sendfn
-
- logical batchopt,firstbatch
- common /batch/batchopt,firstbatch
-
- logical filedel
- common /filest/filedel
-
- integer errorcount
- common /err/errorcount
-
- integer*4 crctable(16),crclword,lib$crc
- integer*2 highword ! highword just spaceholder for crclword
- byte highbyte,lowbyte
- common /crcval/crctable,lowbyte,highbyte,highword
- equivalence (lowbyte,crclword)
-
- c obsolete version will be useful for non-VAX implementations
- c integer high,low
- c byte highbyte,lowbyte
- c common /crcval/high,low
- c equivalence (high,highbyte)
- c equivalence (low,lowbyte)
-
- logical crc
- byte checksumbyte
- integer checksum
- common /checks/checksum,crc
- equivalence (checksum,checksumbyte)
-
- equivalence (ic,c)
-
- c define ascii characters
- parameter NUL=0 !ignore at SOH time
- parameter SOH=1 !start of header for sector
- parameter EOT=4 !end of transfer
- parameter ACK=6 !acknowlege sector
- parameter BEL=7 !bell warning if stupid
- parameter NAK=21 !not acknowlege sector
- parameter CAN=24 !cancel transfer
- parameter CRCCHAR='C' !CRC indicating character
-
- c timeouts
- parameter respnaklim=10 !seconds to allow for response to NAK
- parameter naklim=10 !seconds to allow to receive first NAK
- parameter eotlim=10 !seconds to wait for EOT acknowlege
-
- parameter errlim=10 !max errors on a sector
-
- c define an exit routine to get control on all exits to turn off
- c passall and for debug cleanup
- external giveup
- call userex( giveup )
-
- print *,' XMODEM Version 5.5 3/13/84 [BATCH capable]'
-
- c assign terminal channel for QIO calls to send raw bytes.
- call sys$assign('TT',chan,,)
- c construct CRC table for use by LIB$CRC()
- call lib$crc_table( '102010'o, crctable )
-
- c get command line
- call lib$get_foreign(line,'$_Command: ',,)
- c trim blanks
- do i=80,1,-1
- length=i
- if(line(i:i).NE.' ') goto 25
- enddo
- c no command on line
- 25 continue
-
- c separate options from filename
- c print *,' length=',length
- seploc = index( line(1:length+1),' ' ) ! +1 so find end if one argument
- c print *,' seploc=',seploc
- options=line(1:seploc-1)
- filein=line(seploc+1:length)
- c print *,'options*',options(1:seploc-1),'*'
- lengthin=length-seploc
- if(lengthin.gt.0) then ! make sure not index infinite length string
- if( index( filein(1:lengthin), ' ' ) .ne. 0 ) then
- c print *,'filein*',filein(1:lengthin),'*'
- c print *,'index( filein,'' '')',index(filein(1:lengthin),' ')
- print *,' too many arguments'
- goto 150
- endif
- endif
-
- filedel=.false.
- c parse the options
- batchopt=.false.
- firstbatch=.false.
- textopt=.false.
- sendopt=.false.
- recvopt=.false.
- crc=.false.
- i=0
- if( index(options,'B').NE.0 ) then
- batchopt=.true.
- firstbatch=.true.
- i=i+1
- endif
- if( index(options,'T').NE.0 ) then
- textopt=.true.
- i=i+1
- endif
- if( index(options,'S').NE.0 ) then
- sendopt=.true.
- i=i+1
- endif
- if( index(options,'R').NE.0 ) then
- recvopt=.true.
- i=i+1
- endif
- if( index(options,'C').NE.0 ) then
- crc=.true.
- i=i+1
- endif
-
- c check options
- if(i.ne.seploc-1) then
- print *,char(BEL),' unsupported options ignored'
- print *
- endif
- if(sendopt.and.recvopt) then ! send and receive simultaneously
- print *,' incompatible options SEND and RECEIVE'
- call exit
- endif
- if( .not.(recvopt.and.batchopt) .and. lengthin.le.0 ) then
- c no options or no filename
- print *,' insufficient arguments'
- goto 150
- endif
- if( lengthin.gt.0 .and. (recvopt.and.batchopt) ) then
- print *,' filename ignored on batch receive',char(BEL)
- endif
-
-
- context=0 ! initial FAB pointer for LIB$FILE_FIND
- call passall(CHAN,.TRUE.) ! turn on passall so typeahead
- ! not strip parity on unsolicited chars
- c BATCH option loop comes here
- 100 continue !GOTO at end comes here for next filename
-
- c open separate log file for each transferred file.
- openok=.true.
- workf='XMODEM.WRK'
- worklen=10
- open(8,file='XMODEM.LOG', iostat=istat,
- 1 carriagecontrol='LIST',status='NEW')
- if(istat.ne.0) then
- if(firstbatch) then
- print *,' Can''t open XMODEM.LOG in this directory,'
- print *,' putting it in your main directory.',char(BEL)
- endif
- open(8,file='SYS$SCRATCH:XMODEM.LOG',
- 1 carriagecontrol='LIST',status='NEW')
- openok=.false.
- workf='SYS$SCRATCH:XMODEM.WRK'
- worklen=22 ! number of chars in file name
- endif
-
- if(recvopt) then ! wildcards done on other computer
- if(.not.batchopt) then
- file=filein
- length=lengthin
- endif
- else ! sending, need name(s)
- istat=lib$find_file(filein(1:lengthin),file,context,,)
- if(istat.eq.rms$_nmf) then ! no more files
- if(batchopt) then !await rcvr's request for filename
- call waitnlp(80)
- call ttyout(ACK,1) ! tell yes file
- endif
- call ttyout(EOT,1) ! tell other computer no more
- ! it receives EOT as first
- ! char of expected filename
- c print *,' All transfers complete.'
- write(8,*) ' All transfers complete.'
- close(8,dispose='delete') ! .LOG file
- call exit
- endif
- if(.not.istat) then
- if(firstbatch.or..not.batchopt) then
- print *,' LIB$FILE_FIND error'
- endif
- write(8,*) ' LIB$FILE_FIND error'
- call cancel
- endif
- c trim blanks
- do i=128,1,-1
- length=i
- if(file(i:i).NE.' ') goto 125
- enddo
- c print *,' couldn''t happen, filename blank'
- write(8,*) ' couldn''t happen, filename blank'
- 125 continue
-
- endif
-
- if( sendopt ) then
- c send
- if(batchopt) then
- c make a reasonable filename
- call cleansfn( file(1:length),filec,leng)
- if(firstbatch) then
- print *,' sending BATCH mode, please run receiver'
- endif
- call sendfn( filec(1:leng) )
- endif
- if(textopt) then
- if(.not.batchopt) then ! not batch
- print *,' Sending Text File: ',file(1:length)
- print *,' Do not run your receiver yet.'
- endif
- call vtoc( file(1:length), workf(1:worklen) )
- c print *,' file converted'
- c write(8,*) ' file converted'
- filedel=.true. !delete working file when done
- call sendfile( workf(1:worklen) )
- else ! not text
- if(.not.batchopt) then
- print *,' Sending File: ',file(1:length)
- endif
- call sendfile( file(1:length) )
- endif
-
- elseif(recvopt) then
- c receive
- if(batchopt) then
- if(firstbatch) then
- print *, ' Receiving BATCH please run sender'
- endif
- if(.not.getfn(filed,leng)) then
- call ttyout(EOT,1)
- c print *,' All transfers complete.'
- write(8,*) ' All transfers complete.'
- close(8,dispose='delete') ! log file
- call exit
- endif
- call cleangfn(filed(1:leng),file,length)
- endif
- if(textopt) then
- if(.not.batchopt) then
- print *,' Receiving Text File: ',file(1:length)
- endif
- call recvfile( workf(1:worklen) )
- filedel=.true. !delete working file when done
- call ctov( workf(1:worklen), file(1:length) )
- else ! not text
- if(.not.batchopt) then
- print *,' Receiving File: ',file(1:length)
- endif
- call recvfile( file(1:length) )
- endif
- else
- c else bad command
- 150 print *,' Invalid XMODEM Command --'
- print *,' Usage: XMODEM <SRCTB> <file> '
- print *,' S = Send, R = Receive, C = Use CRCs, B = Batch'
- print *,' T = Convert text files to/from CP/M or VAX/VMS'
- endif
-
- if( batchopt ) then
- firstbatch=.false. ! don't print informational messages
- ! from now on
- goto 100 ! get next filename
- endif
-
- 200 call exit ! should probably have a unified exit here ??
-
- end
- c------------------------------------------------------
- subroutine cleansfn(file,fileclean,length)
- character*(*) file, fileclean
- integer length
- c clean send file name
- c remove too-specific parts of filename (directory and version)
- c and make understandable by CP/M 11 char no dot, last 3 for type
-
- fileclean=' '
- start=index( file,']' )+1
- end=index( file, ';' )-1
- dot = start-1 + index( file(start:end),'.' ) ! VMS guarantees a dot
- if(start.ne.dot) fileclean(1:)=file(start:dot-1)
- if(dot.ne.end) fileclean(9:)=file(dot+1:end)
- ! note: may overwrite last char of vax 9 char filename before dot
- length=11
- return
-
- end
-
- c-------------------------------------
- subroutine sendfn(file)
- character*(*) file
- c sends name for batch checksummed send
-
- byte c
- integer ic
- equivalence (ic,c)
-
- logical ttyinlim
-
- logical crc
- byte checksumbyte
- integer checksum
- common /checks/checksum,crc
- equivalence (checksum,checksumbyte)
-
- parameter BDNMCH=117 ! badname character 'u'
- parameter OKNMCH=6 ! good name character
- parameter ACK=6 ! acknowlege character
- parameter EOF=26 ! filename terminator
-
- 100 continue
- c print *,' Awaiting name NAK'
- c write(8,*) ' Awaiting name NAK'
- call waitnlp(80) ! await NAK
- call ttyout(ACK,1) ! tell receiver a filename follows
-
- checksum=0
- c print *,file
- c write(8,*) file
- do i=1,len(file)
- c=ichar( file(i:i) )
- c print *, ' filename character=',c
- c write(8,*) ' filename character=',c
- checksum=checksum+c
- c print *,' checksum=',checksum
- c write(8,*) ' checksum=',checksum
- call ttyout(c,1)
- 200 if( .not.ttyinlim(c,1,1) ) then
- c print *,' timeout during name'
- write(8,*) ' timeout during name'
- goto 300
- endif
- c print *,' ACK char received decimal=',c
- c write(8,*) ' ACK char received decimal=',c
- if(c.ne.ACK) goto 200 ! let it time out if bad eat chars ?
- enddo
- c print *,' EOF end of filename'
- c write(8,*) ' EOF end of filename'
- checksum=checksum+EOF
- call ttyout(EOF,1)
- if( .not.ttyinlim(c,1,1) ) then ! checksum from receiver (MODEM765.ASM
- ! did not check for timeout)
- c print *,' timeout awaiting checksum in sendfn'
- write(8,*) ' timeout awaiting checksum in sendfn'
- goto 300
- endif
- if( checksumbyte.ne.c ) then
- c bad filename transmission
- c print *,' checksum,byte,c=',checksum,checksumbyte,c
- write(8,*) ' checksum,byte,c='
- write(8,'(3z10)') checksum,checksumbyte,c
- 300 continue
- c print *,' BDNMCH = u'
- c write(8,*) ' BDNMCH = u'
- call ttyout(BDNMCH,1) ! lower case u (but receiver
- ! only cares that it was not ACK)
- c print *,' receiver better NAK now to start again'
- goto 100
- endif
- c print *,' filename sent ok'
- c write(8,*) ' filename sent ok'
- call ttyout(OKNMCH,1) ! ACK
- return
- end
-
- c---------------------------------------------------------
- subroutine waitnlp(sec)
- integer sec
- c Await NAK, Cancel if not here in sec seconds, or if CAN, ignore garbage
-
- integer count
- logical ttyinlim
- byte c
- parameter NAK=21
- parameter CAN=24
-
- count=0
- 100 if( .not.ttyinlim(c,1,1) ) then ! timeout
- count=count+1
- c print *,' waitnlp passed limit'
- write(8,*) ' waitnlp passed limit'
- if(count.ge.sec) call cancel ! passed limit
- goto 100
- elseif( c.eq.CAN ) then
- c print *,' waitnlp canceled'
- write(8,*)' waitnlp canceled'
- call cancel
- elseif( c.ne.NAK ) then ! ignore garbage
- c print *,' waitnlp not NAK, got decimal=',c
- write(8,*) ' waitnlp not NAK, got decimal=',c
- goto 100
- endif
- c must have gotten NAK
- return
-
- end
- c---------------------------------------
- logical function getfn(file,length)
- character*(*) file
- integer length
- c get the characters of the batch mode filename (return false if no more)
- c note: must be declared in callers too.
-
- logical ttyinlim, hsnak
-
- integer ic ! so char(ic) works
- byte c
-
- logical crc
- byte checksumbyte
- integer checksum
- common /checks/checksum,crc
- equivalence (checksum,checksumbyte)
-
- parameter EOT=4 ! end of batch transfer
- parameter ACK=6 ! acknowledge character
- parameter OKNMCH=6 ! OK name character ACK
- parameter EOF=26 ! end of filename
-
- getfn=.true.
- 100 if( .not.hsnak() ) goto 100 ! may hang 'til CTRL-X
-
- checksum=0
- length=0
- file=' ' ! blank filename
- 200 if( .not.ttyinlim(ic,1,1) ) then
- c print *,' Time out receiving filename'
- write(8,*) ' Time out receiving filename'
- goto 100 ! give up and restart handshaking
- endif
- length=length+1
- file(length:length)=char(ic)
- c print *,' filename char=',ic
- c write(8,*) ' filename char=',ic
- c print *,' filename=',file(1:length)
- c write(8,*) ' filename=',file(1:length)
- checksum=checksum+ic
-
- if(ic.eq.EOT) then ! no more filenames
- c write(8,*) ' getfn got EOT'
- getfn=.false.
- return
- endif
-
- if(ic.eq.EOF) then
- length=length-1
- c print *,' getfn got EOF'
- c write(8,*) ' getfn got EOF'
- c print *,file(1:length)
- write(8,*) file(1:length)
- call ttyout(checksumbyte,1) ! send calculated checksum
- if(.not.ttyinlim(c,1,1) ) then ! get verification of checksum
- ! MODEM765 had no timeout check
- c print *,' timeout awaiting checksum ok'
- write(8,*) ' timeout awaiting checksum ok'
- goto 100 ! restart handshake
- endif
- if(c.eq.OKNMCH) return
-
- c print *,' Checksum error, verification c=',c
- write(8,*) ' Checksum error, verification c=',c
- goto 100 ! restart handshaking
- endif
-
- call ttyout(ACK,1)
-
- if(i.gt.128) then ! note: match dimension of "file" in main
- c print *,' Too many characters in filename'
- write(8,*) ' Too many characters in filename'
- goto 100 ! start again at NAK
- endif
- goto 200 ! get next char
-
- end
-
- c--------------------------------------
- logical function hsnak()
- c true if get ACK in response to NAK, c returns null if timeout ???
- c note: must be declared in callers too.
-
- byte c
- logical ttyinlim
- parameter ACK=6
- parameter CAN=24
- parameter NAK=21
-
- call ttyout(NAK,1)
- c checking for CAN is the only way to get out of the loop that
- c calls hsnak
- if( .not.ttyinlim(c,1,2) ) then ! timeout don't care what c is
- write(8,*) ' hsnak timeout'
- hsnak=.false.
- elseif(c.eq.ACK) then
- hsnak=.true.
- c print *,' hsnak got ACK'
- c write(8,*) ' hsnak got ACK'
- elseif(c.eq.CAN) then
- write(8,*) ' hsnak canceled'
- call cancel
- c else ! bad character, ignore
- endif
- return
-
- end
- c------------------------------------------------------
- subroutine cleangfn(file,fileclean,length)
- character*(*) file, fileclean
- integer length
- c clean get file name
- c and make understandable by VAX 13 char with dot, last 3 for type
- c should also replace non-alphanumeric
-
- leng=index(file//' ',' ')-1 ! add blank in case none in filename
- c print *,' leng=',leng
- leng=min(leng,8) ! in case filename and type run together
- c print *,' leng=',leng
- fileclean(1:)=file(1:leng)//'.'//file(9:)
- length=index(fileclean,' ')-1
- c print *,' length=',length
- c write(8,*) ' cleaned filename VAX form*',fileclean(1:length),'*'
- return
- end
- c----------------------------------------------------------------
- c send file
- subroutine sendfile(file)
-
- c declare variables
-
- INTEGER*2 CHAN,STATUS(4)
- COMMON /QIO/ CHAN,STATUS
-
- character*(*) file
-
- byte sectorread(128), sector(130), send(133), c
- equivalence (send(4), sector(1), sectorread(1) )
-
- integer nakwait, stat, ic
- logical ttyinlim
- logical charintime, acked
-
- logical batchopt, firstbatch
- common /batch/batchopt,firstbatch
-
- logical filedel
- common /filest/filedel
-
- integer blocknumber
- byte blockbyte
- equivalence (blocknumber,blockbyte)
-
- integer notblocknumber
- byte notblockbyte
- equivalence (notblocknumber,notblockbyte)
-
- integer errorcount
- common /err/errorcount
-
- integer*4 crctable(16),crclword,lib$crc
- integer*2 highword ! highword just spaceholder for crclword
- byte highbyte,lowbyte
- common /crcval/crctable,lowbyte,highbyte,highword
- equivalence (lowbyte,crclword)
-
- c sector string descriptor to pass to LIB$CRC
- integer*2 le
- byte ty,cl
- integer*4 ad
- common /sectordescriptor/le,ty,cl,ad !length,type,class,address
- data le,ty,cl/130,14,1/
-
-
- c obsolete version will be useful for non-VAX versions
- c integer high,low
- c byte highbyte,lowbyte
- c common /crcval/high,low
- c equivalence (high,highbyte)
- c equivalence (low,lowbyte)
-
- logical crc
- byte checksumbyte
- integer checksum
- common /checks/checksum,crc
- equivalence (checksum,checksumbyte)
-
- equivalence (ic,c)
-
- c 16 bit negative one for LIB$CRC
- parameter neg1='FFFF'x
- c define ASCII characters
- parameter NUL=0
- parameter SOH=1
- parameter EOT=4
- parameter ACK=6
- parameter NAK=21
- parameter CAN=24
- parameter CRCCHAR='C'
- c timeouts
- parameter respnaklim=10
- parameter naklim=10
- parameter eotlim=10
- parameter errlim=10
-
- ad=%loc(sector) ! must be assigned dynamically
-
- open(9,name=file,iostat=stat,status='OLD')
- c 1 carriagecontrol='NONE',recordtype='FIXED',recl=128)
-
- if(stat) then
- if(.not.batchopt) then
- print *,'Can''t open ',file,' for send.'
- endif
- write(8,*) 'Can''t open ',file,' for send.'
- call cancel
- endif
- if( .not.batchopt ) then
- print *,file,' Open -- Please Run Your Receiver --'
- print *
- endif
- errorcount=0
- blocknumber=1
- nakwait=0
-
- c await first NAK (or 'C') indicating receiver is ready
- 200 charintime=ttyinlim(c,1,naklim) ! return NUL if timeout
- c print *,' first NAK character=',c
- c write(8,*) ' character=',c
- if( .NOT.charintime ) then
- write(8,*) ' initial NAK or C timeout, trying again'
- nakwait=nakwait+1
- c give the turkey 80 seconds to figure out how to receive a file
- if(nakwait.ge.80/naklim) call cancel
- goto 200
- elseif(c.EQ.NAK) then
- crc=.false.
- c print *,' CHECKSUM mode'
- write(8,*) ' CHECKSUM mode'
- elseif(c.EQ.CRCCHAR) then
- crc=.true.
- c print *,' CRC mode'
- write(8,*) ' CRC mode'
- elseif(c.EQ.CAN) then
- call cancel
- else
- c unrecognized character
- write(8,*) 'unrecognized first NAK=',c
- nakwait=nakwait+1
- if(nakwait.ge.80/naklim) call cancel
- goto 200
- endif
-
- 300 continue
- c send new sector
- c use equivalence so not need to do inefficient implicit do loop in read
- read(9,1000,end=500) sectorread
- 1000 format(128a)
- errorcount=0
- c print *,' sector as read',sector
- c write(8,*) ' sector as read',sector
- 400 continue
- c send sector
- c print *,' SOH '
- c write(8,*) ' SOH'
- send(1)=SOH
- c note: equivalence used for fast integer to byte conversion
- c without byte overflow problems
- send(2)=blockbyte
- notblocknumber=not(blocknumber)
- send(3)=notblockbyte
- c print *,' blocknumber=',blocknumber
- c write(8,*) ' blocknumber=',blocknumber
-
- c sector already in sending buffer done by equivalence
-
- checksum=0
- c call clrcrc
- c calc checksum or crc
- if(crc) then
- c write(8,*) ' CRC mode'
- c put all bytes + two finishing zero bytes through CRC calculation
- sector(129)=0
- sector(130)=0
- crclword=lib$crc( crctable, 0, le ) ! le= sector string descr
- c obsolete version useful for non-VAX version
- c call updcrc( sector,130 )
- send(132)=highbyte ! equivalenced to crclword
- send(133)=lowbyte ! equivalenced to crclword
- c write(8,*) 'highbyte,lowbyte'
- c write(8,'(2z10)') highbyte,lowbyte
- c actually send
- call ttyout(send,133)
- else
- c write(8,*) 'CHECKSUM mode'
- do i=1,128
- checksum=checksum+sector(i)
- enddo
- c this sends low order byte of checksum
- send(132)=checksumbyte
- c print *,' checksumbyte ',checksumbyte
- c write(8,*) ' checksumbyte ',checksumbyte
- call ttyout(send,132)
- endif
-
- c sector sent, see if receiver acknowleges
- c getack attempts to get ACK
- c if not, repeat sector
- c print *, ' should wait for ACK 10 seconds'
- c write(8,*) ' should wait for ACK 10 seconds'
-
- call getack(acked)
- c print *, ' getack returned=',acked
- c write(8,*) ' getack returned=',acked
- if(.NOT.acked) goto 400
-
- c ACK received, send next sector
- blocknumber=blocknumber+1
- goto 300
-
- c end of file during read. finish up sending.
- 500 continue
- call ttyout(EOT,1)
- c getack attempts to get ACK up to errlim times
- call getack(acked)
- if( .NOT.acked ) goto 500
-
- c print *,' This file Sending complete.'
- write(8,*) ' This file Sending complete.'
- if (filedel) then
- close(9,dispose='DELETE')
- else
- close(9)
- endif
- close(8,dispose='DELETE') ! the .LOG file
- return
- end
-
- c----------------------------------------------------------------
- c receive file
- subroutine recvfile(file)
-
- c declare variables
-
- INTEGER*2 CHAN,STATUS(4)
- COMMON /QIO/ CHAN,STATUS
-
- character*(*) file
- byte c, notc, ck
- integer blocknumber, inotc, notnotc, secbytes, stat
- integer testblock, testprev, ic
- logical ttyinlim
- logical charintime, firstsoh
-
- byte sector(130),sectorwrite(128)
- equivalence (sector,sectorwrite)
-
- logical batchopt,firstbatch
- common /batch/batchopt,firstbatch
-
- integer errorcount
- common /err/errorcount
-
- integer*4 crctable(16),crclword,lib$crc
- integer*2 highword ! highword just spaceholder for crclword
- byte highbyte,lowbyte
- common /crcval/crctable,lowbyte,highbyte,highword
- equivalence (lowbyte,crclword)
-
- c sector string descriptor to pass to LIB$CRC
- integer*2 le
- byte ty,cl
- integer*4 ad
- common /sectordescriptor/le,ty,cl,ad !length,type,class,address
- data le,ty,cl/130,14,1/
-
- logical crc
- byte checksumbyte
- integer checksum
- common /checks/checksum,crc
- equivalence (checksum,checksumbyte)
-
- equivalence (ic,c)
-
- c 16 bit negative one for LIB$CRC
- parameter neg1='FFFF'x
- c define ASCII characters
- parameter NUL=0
- parameter SOH=1
- parameter EOT=4
- parameter ACK=6
- parameter NAK=21
- parameter CAN=24
- parameter CRCCHAR='C'
- c timeouts
- parameter respnaklim=10
- parameter naklim=10
- parameter eotlim=10
- parameter errlim=10
- parameter datalim=2 ! timeout for data block receive
- ! 1 second wouldn't work on moderately loaded
- ! VAX, more may be necessary if heavily loaded
-
- ad=%loc(sector) ! for sector string descriptor must be dynamic
-
- open(7,name=file,recl=128,status='NEW',iostat=stat,
- 1 carriagecontrol='NONE',recordtype='FIXED')
- if(stat) then
- if(batchopt) then
-
- c print *,' Can''t open ',file,' for receive.'
- write(8,*) ' Can''t open ',file,' for receive.'
- else
- print *,' Can''t open ',file,' for receive.'
- write(8,*) ' Can''t open ',file,' for receive.'
- endif
- call cancel
- endif
-
- if(.not.batchopt) then
- print *,' Please Send Your File --'
- print *
- endif
-
- if(crc) then
- secbytes=130
- else ! checksum mode
- secbytes=129
- endif
-
- firstsoh=.false.
- errorcount=0
- blocknumber=1
-
- c start the sender by letting ttyinlim time-out in getack routine
- c so it sends a NAK or C
- goto 999
-
- 800 continue
- c write(8,*) ' ready for SOH'
- c must allow enough time for other's disk read (xmodem50.asm allows 10sec)
- charintime=ttyinlim(c,1,respnaklim)
- c if no char for a while, try NAK or C again
- if( .NOT.charintime ) then
- c print*,' no response to NAK or C, trying again'
- write(8,*) ' no response to NAK or C, trying again'
- goto 999
- endif
- c else received a char so see what it is
- if(c.eq.NUL) goto 800 ! ignore nulls here for compatablity with old
- ! versions of modem7
- if(c.EQ.CAN) then
- c print *,' Canceled. Aborting.'
- write(8,*) ' Canceled. Aborting.'
- call exit
- endif
-
- c print *,' EOT or SOH character=',c
- c write(8,*) ' EOT or SOH character=',c
- if(c.NE.EOT) then
- IF(c.NE.SOH) then
- c print *,' Not SOH, was decimal ',c
- write(8,*) ' Not SOH, was decimal ',c
- goto 999
- endif
- firstsoh=.true.
-
- c character was SOH to indicate start of header
- c get block number and complement
- charintime=ttyinlim(c,1,1)
- if(.not.charintime) then
- c print *,' timeout awaiting block number'
- write(8,*) ' timeout awaiting block number'
- goto 999
- endif
- c print *,' block=',c
- c write(8,*) ' block=',c
-
- charintime=ttyinlim(notc,1,1)
- if(.not.charintime) then
- c print *,' timeout awaiting block complement'
- write(8,*) ' timeout awaiting block complement'
- goto 999
- endif
- c print *,' block complement=',notc
- c write(8,*) ' block complement=',notc
- inotc=notc ! make integer for "not" function
- notnotc=iand( not(inotc),255 ) ! mask back to byte
-
- c c is low order byte of ic via equivalence statement
- if(ic.NE.notnotc) then
- c print *,' block check bad.'
- write(8,*) ' block check bad.'
- goto 999
- endif
- c block number valid but not yet checked against expected
-
- c clear checksum and CRC
- checksum=0
- c call clrcrc
-
- c receive the sector and checksum bytes in one call (for speed) and to
- c keep from hogging VAX cpu time at high baud rates.
- c secbytes is 129 for checksum, 130 for CRC
- charintime=ttyinlim(sector,secbytes,datalim)
- C check for time out
- if(.not.charintime) then
- c print *,' Timeout on data block read'
- write (8,*) ' Timeout on data block read'
- goto 999
- endif
-
- if(crc) then
- c put data AND CRC bytes through updcrc
- crclword=lib$crc(crctable,0,le) !le=sector string descr
- c obsolete version useful for non-VAX versions
- c call updcrc(sector,secbytes)
-
- c if result non-zero, BAD.
- if(highbyte.NE.0 .OR.
- 1 lowbyte.NE.0 ) then
- c print *,' CRC, high,low='
- write(8,*) ' CRC, high,low='
- c print 3000, highbyte,lowbyte
- write(8,3000) highbyte,lowbyte
- 3000 format(2z10)
- goto 999
- endif
- else
- c don't add received checksum byte to checksum
- do i=1,secbytes-1
- checksum=checksum+sector(i)
- enddo
- ck=sector(129)
- c print 2100, ck
- c write(8,2100) ck
-
- c print 2100, checksum
- c write(8,2100) checksum
- c print 2100, checksumbyte
- c write(8,2100) checksumbyte
- c 2100 format(' checksum=',z10)
- if( checksumbyte.NE.ck ) then
- write(8,*) ' bad checksum'
- goto 999
- endif
- endif
-
- c received OK so we can believe the block number, see which block it was
- c mask it to be one byte
- testblock=iand(blocknumber,255)
- testprev=iand( blocknumber-1 ,255)
- if( ic.EQ.testprev) then
- c print *, ' prev. block again, out of synch'
- write(8,*) ' prev. block again, out of synch'
- c already have this block so don't write it, but ACK anyway to resynchronize
- goto 985
- elseif( ic.NE.testblock ) then
- c print *, ' block number bad.'
- write(8,*) ' block number bad.'
- goto 999
- endif
- c else was expected block
-
- c write before acknowlege so not have to listen while write.
- c equivalence so not need inefficient implicit do loop
- write(7,2000,err=900) sectorwrite
- 2000 format(128a)
- goto 975
-
- 900 write(8,*) ' Can''t write sector. Aborting.'
- c print *, ' Can''t write sector. Aborting.'
- call cancel
-
- 975 continue
- c received sector ok, wrote it ok, so acknowlege it to request next.
- blocknumber=blocknumber+1
- c comes here if re-received the previous sector
- 985 continue
- errorcount=0
- c print *, ' ACKing, sector was ok.'
- c write(8,*) ' ACKing, sector was ok.'
- call ttyout(ACK,1)
- goto 800
-
- c else error so eat garbage in case out of synch and try again
- 999 continue
- call eat
- c print *, ' receive error NAK, block=',blocknumber
- write(8,*) ' receive error NAK, block=',blocknumber
- if(crc.AND..NOT.firstsoh) then
- c keep sending 'C' 'til receive first SOH
- call ttyout(CRCCHAR,1)
- else
- call ttyout(NAK,1)
- endif
- errorcount=errorcount+1
- 998 if(errorcount.GE.errlim) then
- c print *,' Unable to receive block. Aborting.'
- write(8,*) ' Not receive block. Aborting.'
- c delete incompletely received file
- close(7,dispose='DELETE')
- call cancel
- endif
- c retry
- goto 800
- endif
-
- c EOT received instead of SOH so file done.
- c should keep sending ACK 'til no more EOT's ?
- close(9)
- close(7)
- call ttyout(ACK,1)
- call ttyout(ACK,1)
- call ttyout(ACK,1)
-
- write(8,*) ' Completed.'
- c print *, ' Completed.'
- c transfer ok, so delete the error log file.
- close(8,dispose='DELETE')
- return
- end
-
- c-------------------------------------------------------------
- subroutine ctov(input,output)
- c convert file of XMODEM 128 byte records with embedded <CR><LF>
- c marking end-of-line and CTRL-Z marking end-of-file
- c to carriage-control=LIST (normal VAX editable file)
-
- character*80 input,output
- character*300 line
- character*1 CR,LF,recchar
- logical eof, eol
- integer len
-
- logical filedel
- common /filest/filedel
-
- len=0
- eof=.false.
- eol=.false.
- CR=char(13)
- LF=char(10)
-
- open(9,file=input,status='OLD')
- c set maximum output record length to 300 (fortran default is 133)
- open(7,file=output,status='NEW',carriagecontrol='LIST',recl=300)
-
- c getchar (read new record if no input characters left)
- c if EOF on input, write line and exit
- c if CR then
- c if getchar LF then write line
- c else put back char and putchar CR into line (error if too long)
- c endif
- c else putchar (write error message if line too long)
- c endif
- c loop
-
- 100 call getc(recchar,eof,eol)
- if(eof) goto 200
- if(recchar.eq.CR) then
- c PRINT *,' CR'
- call getc(recchar,eof)
- if(eof.or.recchar.ne.LF) then
- call putback
-
- len=len+1
- if(len.ge.301) print *,' Out line too long.'
- c print *,' too long line=',line
- line(len:len)=recchar
- else
- c was LF
- c PRINT *,' LEN=',LEN
- c print *,' after LF, line=',line(1:len)
- write(7,2000) line(1:len)
- len=0
- endif
- else
- c not CR, was "ordinary" character
- len=len+1
- if(len.ge.301) then
- print *,' Out line too long.'
- c PRINT *,' LINE=',LINE(1:len)
- else
- line(len:len)=recchar
- endif
- endif
-
- go to 100
-
- c flush last line and exit
- 200 continue
- if(len.gt.0) then
- write(7,2000) line(1:len)
- 2000 format(a)
- len=0
- endif
- if (filedel) then
- close(9,dispose='DELETE')
- else
- close(9)
- endif
- close(7)
- return
- end
- c------------------------------------------
- subroutine getc(c,eof)
- character*1 c
- logical eof
- c get character from a CP/M text file
- c point to next character in record (read record if necessary)
- character*1 CTRLZ
-
- integer point
- character*128 record
- common /reccom/point,record
- data point/0/
-
- logical firsttime
- common /getccom/firsttime
- data firsttime/.true./
-
- CTRLZ=char(26)
- point=point+1
- if( firsttime .or. (point.gt.128) ) then
- firsttime=.false.
- 100 read(9,1000,end=200) record
- 1000 format(a)
- c PRINT *,RECORD
- point=1
- endif
- c strip parity in case CP/M file had it
- c=char(iand(ichar(record(point:point)),127))
- if(c.eq.CTRLZ) goto 200 ! end of CP/M text file
- return
-
- c end of file
- 200 eof=.true.
- firsttime=.true. ! ready for next file
- point=0
- return
- end
- c----------------------------------------------
- subroutine putback
- c point to previous input character so this character will be getchar result
- c even works if 1st char of record
- integer point
- character*128 record
- common /reccom/point,record
-
- point=point-1
- return
- end
- c-------------------------------------------------------------
- subroutine vtoc(input,output)
- c convert VAX text file to
- c file of XMODEM 128 byte records with embedded <CR><LF>
-
- character*80 input,output
- character*1 CR,LF,c
- logical eof,eol
-
- eof=.false.
- eol=.false.
- CR=char(13)
- LF=char(10)
-
- open(9,file=input,status='OLD',READONLY)
- open(7,file=output,status='NEW',carriagecontrol='LIST',
- 1 recl=128,recordtype='FIXED')
-
- c getchar (read new line if no input characters left)
- c putchar ( output record if full, close if EOF )
- c if EOL on input, putchar CR putchar LF (output record if full)
- c loop
-
- 100 call getv(c,eof,eol)
- if(.not.eol) then
- call putchar(c,eof)
- if(eof) then
- return
- endif
- else
- c end of line
- call putchar(CR,eof)
- call putchar(LF,eof)
- eol=.false.
- if(eof) then
- return
- endif
- endif
- go to 100
-
- end
- c------------------------------------------
- subroutine putchar(c,eof)
- character*1 c
- logical eof
- c put character into record (write record if necessary)
- c if eof, fills out rest of record with CTRL-Z's and exits
- character*1 CTRLZ
-
- integer point
- character*128 record
- common /reccom/point,record
- data point/0/
-
- if(eof) goto 200
- point=point+1
- c strip parity in case VAX file had it
- record(point:point)=char(iand(ichar(c),127))
- c print *,' record(point:point)=',record(point:point)
- c print *,' point=',point
- 50 if(point.ge.128) then
- c print *,' record=',record
- 100 write(7,1000) record
- 1000 format(a)
- point=0
- endif
- return
-
- c EOF fill record with 26's (CTRL-Z, CP/M end of file mark for ASCII)
- c output last record and exit
- 200 continue
- c print *,' in putchar EOF section'
- CTRLZ=char(26)
- do i=point+1,128
- record(i:i)=CTRLZ
- enddo
- c print *,' record=',record
- write(7,1000) record
- close(9)
- close(7)
- point=0 ! ready for next file
- return
- end
- c-------------------------------------------
- subroutine getv(inchar,eof,eol)
- character*1 inchar
- logical eof,eol
- c get character from input line (read line if necessary)
- c returns character and eol=.true. if no more char on line
- c returns eof if end of file (no character)
- character*255 line
- integer len, pos
- logical firsttime
- common/lincom/pos,len,line
- data pos/0/
-
- if(pos.eq.0) then
- read(9,1000,end=100)len,line(1:len)
- 1000 format(q,a)
- c print *,' line=',line
- endif
- pos=pos+1
- if(pos.gt.len) then
- eol=.true.
- pos=0
- return
- endif
- c print *,' pos=',pos,' line(1:pos)=',line(1:pos)
- c print *,' line(pos:pos)=',line(pos:pos)
- inchar=line(pos:pos)
- c print *,' pos,char',pos,inchar
- return
- c EOF
- 100 continue
- eof=.true.
- return
- end
- cc-----------------------------------------------------------
- c subroutine clrcrc
- cc clears CRC
- c integer high,low
- c byte highbyte,lowbyte
- c common /crcval/high,low
- c equivalence (high,highbyte)
- c equivalence (low,lowbyte)
- c
- c high=0
- c low=0
- c return
- c end
- cc-----------------------------------------------------------
- c subroutine updcrc(bbyte,n)
- c byte bbyte(*)
- c integer n
- cc updates the Cyclic Redundancy Code
- cc uses x^16 + x^12 + x^5 + 1 as recommended by CCITT
- cc and as used by CRCSUBS version 1.20 for 8080 microprocessor
- cc and incorporated into the MODEM7 protocol of the CP/M user's group
- c
- cc during sending:
- cc call clrcrc
- cc call updcrc for each byte
- cc call fincrc to finish (or just put 2 extra zero bytes through updcrc)
- cc result to send is low byte of high and low in that order.
- c
- cc during reception:
- cc call clrcrc
- cc call updcrc all bytes PLUS the two received CRC bytes must be passed
- cc to this routine
- cc then zero in high and low means good checksum
- c
- cc see Computer Networks, Andrew S. Tanenbaum, Prentiss-Hall, 1981
- c
- cc must declare integer to allow shifting
- c integer byte
- c integer bit,bitl,bith
- c
- c integer high,low
- c byte highbyte,lowbyte
- c common /crcval/high,low
- c equivalence (high,highbyte)
- c equivalence (low,lowbyte)
- c
- cc write(8,*) ' inside updcrc'
- c do i=1,n
- cc write(8,*) 'high,low,byte'
- cc write(8,1000) high,low,bbyte
- cc1000 format(3z10)
- c byte=bbyte(i)
- c
- c do j=1,8
- cc get high bits of bytes so we don't lose them when shift
- cc positive is left shift
- c bit =ishft( iand(128,byte), -7)
- c bitl=ishft( iand(128,low), -7)
- c bith=ishft( iand(128,high), -7)
- cc write(8,*) 'bit,bitl,bith'
- cc write(8,1000) bit,bitl,bith
- cc get ready for next iteration
- c newbyte=ishft(byte,1)
- c byte=newbyte ! introduced dummy variable newbyte
- c ! to avoid "access violation"
- cc write(8,*) ' byte ready for next iteration'
- cc write(8,1000) byte
- cc shift those bits in
- c low =ishft(low ,1)+bit
- c high=ishft(high,1)+bitl
- cc write(8,*),' high,low after shifting bits in'
- cc write(8,1000) high,low
- c
- c if(bith.eq.1) then
- c high=ieor(16,high)
- c low=ieor(33,low)
- cc write(8,*) ' high,low after xor'
- cc write(8,1000) high,low
- c endif
- c enddo
- c enddo
- c return
- c end
- c-----------------------------------------------------------
- c subroutine fincrc
- c finish CRC calculation for sending result in high, low
- c NEVER ACTUALLY USED. I JUST PASS ZEROES TO UPDCRC.
- c merely runs updcrc with two zero bytes
- c integer high,low
- c byte highbyte,lowbyte
- c common /crcval/high,low
- c equivalence (high,highbyte)
- c equivalence (low,lowbyte)
- c
- c byte=0
- c call updcrc(byte)
- c call updcrc(byte)
- c return
- c end
- c-----------------------------------------------------------
- subroutine eat
- c eats extra characters 'til 1 second pause used to re-synch after error
- byte buffer(135)
- integer numchar
- logical i,ttyinlim
- c
- parameter maxtime=1
- c in case mis-interpreted header, allow at least 1 block of garbage
- numchar=135
-
- i=ttyinlim(buffer,numchar,maxtime)
- c print *,' finished eating'
- c write(8,*) ' finished eating'
- return
- end
- c-----------------------------------------------------------
- LOGICAL FUNCTION TTYINLIM(LINE,N,LIMIT)
- BYTE LINE(*)
- INTEGER N,LIMIT
- C READ CHARACTERS FROM TERMINAL
- C WITH TIME LIMIT, RETURN FALSE IF NO CHARACTERS
- C RECEIVED FOR LIMIT SECONDS
- C MODIFIED BY BELONIS TO REMOVE PRIVILEGE PROBLEM
- C MAY HAVE PROBLEM WITH TYPE-AHEAD
- c apparent typeahead problem: in SENDFN, remote can send checksum
- c too soon after we send EOF, it is seen by typeahead since
- c this routine has not yet activated, so high bit already stripped
- c This was solved by using PASSALL routine.
-
- INTEGER*2 CHAN,STATUS(4)
- COMMON /QIO/ CHAN,STATUS
-
- INCLUDE '($SSDEF)' ! defines error status returns
- INTEGER I
- INTEGER SYS$QIOW
- INTEGER*4 terminators(2)
- EXTERNAL IO$M_NOECHO,IO$_TTYREADALL,IO$M_TIMED
- DATA TERMINATORS/0,0/
- C
- c write(8,*) ' inside ttyinlim'
- TTYINLIM=.TRUE. ! DEFAULT no delay over LIMIT seconds
- I = SYS$QIOW(, !EVENT FLAG
- - %VAL(CHAN), !CHANNEL
- - %VAL(%LOC(IO$_TTYREADALL).OR.
- - %LOC(IO$M_NOECHO).OR.%LOC(IO$M_TIMED)),
- - STATUS,,,
- - LINE, !BUFFER
- - %VAL(N), !LENGTH
- - %VAL(LIMIT), !time limit in seconds
- - terminators,,) !no terminators
- c print *,' ttyinlim=',(LINE(j),j=1,N), ' STATUS=',STATUS
- c write(8,*) ' ttyinlim=',(LINE(j),j=1,N), ' STATUS=',STATUS
- if(STATUS(1).EQ.SS$_TIMEOUT) THEN
- TTYINLIM=.FALSE.
- c print *, ' ttyinlim timeout'
- write(8,*) ' ttyinlim timeout'
- return
- ENDIF
-
- IF (I) THEN
- c print *, ' returning from ttyinlim'
- c write(8,*) ' returning from ttyinlim
- return
- endif
- C
- C ERROR
- write(8,*) ' ttyinlim error.'
- CALL SYS$EXIT( %VAL(I) )
- END
- c-----------------------------------------------------------
- SUBROUTINE TTYOUT(LINE,N)
- BYTE LINE(*)
- INTEGER*2 N
- C output N characters without interpretation
-
- INTEGER*2 CHAN,STATUS(4)
- COMMON /QIO/ CHAN,STATUS
-
- INTEGER I
- INTEGER SYS$QIOW
- EXTERNAL IO$M_NOFORMAT
- EXTERNAL IO$_WRITEVBLK
- C
- IF( N.LE.0 ) THEN
- WRITE(8,*) ' ttyout called with strange number of char ',N
- RETURN
- ENDIF
- C
- c print *, ' to be sent by ttyout ', (line(i),i=1,n)
- c write(8,*) ' to be sent by ttyout ', (line(i),i=1,n)
- I = SYS$QIOW(,
- - %VAL(CHAN),
- - %VAL(%LOC(IO$_WRITEVBLK).OR.
- - %LOC(IO$M_NOFORMAT)),
- - STATUS,,,
- - LINE,
- - %VAL(N),,
- - %VAL(0),, ) !NO CARRIAGE CONTROL
- if(I) then
- return
- endif
- C
- C ERROR
- write(8,*) ' ttyout error.'
- CALL SYS$EXIT( %VAL(I) )
- END
- c--------------------------------------------------
- subroutine giveup
- c this exit routine used especially in case exited via QIO problem
-
- INTEGER*2 CHAN,STATUS(4)
- COMMON /QIO/ CHAN,STATUS
-
- c note: if want log file message, must re-open since
- c system already closed all files before this exit handler got control
- c open(8,file='XMODEM.LOG',access='APPEND')
- c write(8,*) ' Exit handler.'
-
- c turn off passall
- call passall(CHAN,.FALSE.)
- return
- end
- c-----------------------------------------------------
- SUBROUTINE PASSALL(CHAN,SWITCH)
- C sets PASSALL mode for terminal connected to chanel CHAN, ON if switch true
- IMPLICIT INTEGER (A-Z)
- INCLUDE '($TTDEF)'
- INCLUDE '($IODEF)'
- LOGICAL SWITCH
- COMMON/CHAR/CLASS,TYPE,WIDTH,CHARAC(3),LENGTH !byte reversed LENGTH
- BYTE CLASS,TYPE,CHARAC,LENGTH
- INTEGER*2 WIDTH,SPEED
- EQUIVALENCE(CHARACTER,CHARAC)
-
- c sense current terminal driver mode
- ISTAT=SYS$QIOW(,%VAL(CHAN),%VAL(IO$_SENSEMODE),,,,
- 1 CLASS,,,,,)
- IF (.NOT.ISTAT) CALL ERROR('TERMINAL SENSEMODE',ISTAT)
-
- IF(SWITCH) THEN
- c turn on 8 bit passall
- CHARACTER=CHARACTER.OR.TT$M_PASSALL.OR.
- 1 TT$M_EIGHTBIT
- ELSE
- c turn off 8 bit passall
- CHARACTER=CHARACTER.AND..NOT.TT$M_PASSALL.AND.
- 1 .NOT.TT$M_EIGHTBIT
- ENDIF
- SPEED=0 !LEAVE SPEED UNCHANGED
- PAR=0 !LEAVE PARITY UNCHANGED
-
- c set terminal mode with desired passall
- ISTAT=SYS$QIOW(,%VAL(CHAN),%VAL(IO$_SETMODE),,,,
- 1 CLASS,,%VAL(SPEED),,%VAL(PAR),)
- IF (.NOT.ISTAT) CALL ERROR('TERMINAL SETMODE',ISTAT)
- RETURN
- END
- c---------------------------------------------------
- SUBROUTINE ERROR(STRING,MSGID)
- c Types error message
- IMPLICIT INTEGER(A-Z)
- CHARACTER*(*) STRING
- CHARACTER*80 MESSAGE
-
- TYPE *,' *** ERROR: ',STRING
- write(8,*) ' *** ERROR: ',STRING
- CALL SYS$GETMSG(%VAL(MSGID),MSGLEN,MESSAGE,%VAL(15),)
- TYPE *,MESSAGE(1:MSGLEN),CRLF
- write(8,*) MESSAGE(1:MSGLEN),CRLF
- RETURN
- END
- c-----------------------------------------------------------
- subroutine cancel
-
- INTEGER*2 CHAN,STATUS(4)
- COMMON /QIO/ CHAN,STATUS
-
- c called to cancel send (at least)
- logical ttyinlim
- byte c(135) ! enough space to eat everything
- parameter CAN=24
- parameter SPACE=32
-
- c eat garbage
- 100 if( ttyinlim(c,135,1) ) goto 100
- c cancel other end
- call ttyout(CAN,1)
-
- c eat garbage again in case it didn't understand ?
- 200 if( ttyinlim(c,135,1) ) goto 200
- c clear the CAN from far end's input in case he has already cancelled and so
- c has not yet read it.
- c ???? why ? xmodem50.asm does it
-
- call ttyout(SPACE,1)
-
- c print*,' XMODEM program canceled'
- write(8,*)' XMODEM program canceled'
- call exit
- end
- c------------------------------------------------------
- subroutine getack(acked)
- c returns .TRUE. if gets ACK
- logical charintime, ttyinlim, acked
- byte sector(130),c
-
- integer errorcount
- common /err/errorcount
-
- parameter ACK=6
- parameter NAK=21
- parameter CAN=24
- parameter errlim=10 ! max number of errors
- parameter acklim=15 ! seconds to wait for ACK (xmodem.asm uses 10?)
- ! but Stern's Northstar takes longer
- ! to write 128 sectors
-
- c print*,' inside getack'
- c write(8,*) ' inside getack'
- c empty typeahead in case garbage
- c charintime=ttyinlim(sector,130,0)
-
- c allow time for disk file write at other end. Typically 128 sectors.
- c Sometimes only 1 track.
- 10 charintime=ttyinlim(c,1,acklim)
- c print*,' getack got',c
- c write(8,*) ' getack got',c
-
- if( .NOT.charintime ) then
- c print *, ' timeout in GETACK'
- write(8,*) ' timeout in GETACK'
- errorcount=errorcount+1
- if(errorcount.GE.errlim) then
- write(8,*) ' not acknowleged in 10 tries.'
- c print *,' Can''t send sector. Aborting.'
- call cancel
- endif
- goto 10 ! try again
- elseif( c.EQ.ACK ) then
- c received ACK
- acked=.TRUE.
- elseif( c.EQ.NAK ) then
- print *,' not ACK, decimal=',c
- write(8,*) ' not ACK, decimal=',c
- errorcount=errorcount+1
- if(errorcount.GE.errlim) then
- write(8,*) ' not acknowleged in 10 tries.'
- c print *,' Can''t send sector. Aborting.'
- call cancel
- endif
- acked=.FALSE.
-
- elseif(c.EQ.CAN) then
- write (8,*) 'Cancel received while waiting for ACK'
- call cancel
- else
- c received garbage, ignore it and try again.
- c note: this risks seeing ACK inside the burst of garbage, possibly should EAT
- c print *, ' not ACK, decimal=',c
- write(8,*) ' not ACK, decimal=',c
- goto 10
- endif
- return
- end